package com.loe.ui.view

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.*
import android.graphics.drawable.Drawable
import android.text.InputFilter
import android.text.InputFilter.LengthFilter
import android.text.InputType
import android.text.TextUtils
import android.text.method.DigitsKeyListener
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.widget.EditText
import androidx.annotation.Keep
import com.loe.formview.DecimalInputFilter
import com.loe.mvp.ext_java.float
import com.loe.mvp.ext_view.addTextAfterListener
import com.loe.ui.*
import com.loe.ui.api.EditTextApi
import com.loe.ui.api.IUiView
import com.loe.ui.page.UiPage
import com.quickjs.JSArray
import com.quickjs.JSObject
import java.util.*

@Keep
@SuppressLint("AppCompatCustomView")
open class UiEditText : EditText, IUiView
{
    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    {
        initXML(attrs)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        initXML(attrs)
    }

    private fun initXML(attrs: AttributeSet)
    {
//        val array = context.obtainStyledAttributes(attrs, R.styleable.UiTextView)
//
//        if (array.getBoolean(R.styleable.UiTextView_ui_delete, false))
//        {
//            paint.flags = Paint.STRIKE_THRU_TEXT_FLAG
//            paint.isAntiAlias = true
//        }
//
//        if (array.getBoolean(R.styleable.UiTextView_ui_under, false))
//        {
//            paint.flags = Paint.UNDERLINE_TEXT_FLAG
//            paint.isAntiAlias = true
//        }
//
//        array.getString(R.styleable.UiTextView_ui_bg)?.let { bg = it }
//
//        array.recycle()
    }

    init
    {
        setBackgroundColor(Color.TRANSPARENT)
    }

    override val jsObject by lazy { EditTextApi(this).jsObject }

    override fun setUI(ui: JSObject, uiPage: UiPage?): View
    {
        // click
        ui.gotHasBoolean("isClick") { setClick(it) }
        // textColor
        ui.gotHasString("textColor") { setTextColor(it.color) }

        // gravity
        ui.gotHasGravity("gravity") { gravity = it }

        // isTextSelectable
        ui.gotHasBoolean("isTextSelectable") { setTextIsSelectable(it) }
        // hint
        ui.gotHasString("hint") { hint = it }
        // hintColor
        ui.gotHasString("hintColor") { setHintTextColor(it.color) }
        // minLines
        ui.gotHasInt("minLines") { minLines = it }
        // maxLines
        ui.gotHasInt("maxLines")
        {
            maxLines = it
            if (maxLines == 1) setSingleLine(true)
        }
        // ellipsize
        ui.gotHasString("ellipsis") { ellipsize = TextUtils.TruncateAt.valueOf(it.toUpperCase()) }

        // bold
        ui.gotHasBoolean("bold") { setBold(it) }
        // italic
        ui.gotHasBoolean("italic") { setItalic(it) }
        // textStyle
        ui.gotHasString("textStyle") { setTextStyle(it) }

        // onText
        ui.gotHasFunction("onText")
        { callback ->
            setTextListener { callback.call(jsObject, JSArray(jsContext).push(it)) }
        }
        // textSize
        ui.gotHasString("textSize") { setTextSize(it) }

        // autoVisible
        ui.gotHasBoolean("autoVisible") { isAutoVisible = it }
        // text
        ui.gotHasString("text") { setAutoText(it) }

        // clear
        ui.gotHasBoolean("isClear")
        {
            if (ui.contains("clearColor"))
            {
                initClear(it, ui.gotString("clearSize", "24").px, ui.gotString("clearColor").color)
            } else
            {
                initClear(it, ui.gotString("clearSize", "24").px)
            }
        }

        // editType
        ui.gotHasString("editType")
        {
            inputType = when (it)
            {
                "pass" -> INPUT_PASSWORD
                "number" -> INPUT_NUMBER
                "decimal" -> INPUT_DECIMAL
                "textCode" -> INPUT_TEXT_CODE
                else -> INPUT_TEXT
            }
        }

        // limitNumber
        ui.gotHasInt("limitNumber") { limitNumber = it }
        // limitDecimal
        ui.gotHasInt("limitDecimal") { limitDecimal = it }
        // maxLen
        ui.gotHasInt("maxLen") { maxLenFilter = LengthFilter(it) }
        resetLimit()

        // filter
        ui.gotHasString("filter") { setFilter(it) }

        return this
    }

    override var onSelect: (() -> Unit)? = null

    /******************************************* 清除 *******************************************/

    private var isClear = false

    private fun initClear(isClear: Boolean, clearSize: Int, clearColor: Int? = null)
    {
        this.isClear = isClear
        if (!isClear) return

        var clearDrawable = compoundDrawables[2]
        if (clearDrawable == null)
        {
            clearDrawable = resources.getDrawable(R.mipmap.icon_clear_gray, context.theme)
        }
        clearDrawable.setBounds(0, 0, clearSize, clearSize)
        if (clearColor != null) clearDrawable.colorFilter = PorterDuffColorFilter(clearColor, PorterDuff.Mode.SRC_ATOP)

        fun setClearIconVisible(visible: Boolean)
        {
            val right: Drawable? = if (visible) clearDrawable else null
            setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], right, compoundDrawables[3])
        }

        // 默认设置隐藏图标
        setClearIconVisible(false)
        // 设置焦点改变的监听
        var hasFocus = false
        // 设置输入框里面内容发生改变的监听
        setOnFocusChangeListener()
        { v, hFocus ->
            hasFocus = hFocus
            setClearIconVisible(hasFocus && text.isNotEmpty())
        }
        addTextAfterListener()
        {
            if (hasFocus)
            {
                setClearIconVisible(text.isNotEmpty())
            }
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean
    {
        if (isClear && event.action == MotionEvent.ACTION_UP)
        {
            if (compoundDrawables[2] != null)
            {
                val touchable = event.x > width - totalPaddingRight &&
                    event.x < width - paddingRight
                if (touchable)
                {
                    setText("")
                }
            }
        }
        return super.onTouchEvent(event)
    }

    /******************************************* 处理 *******************************************/

    private var maxLenFilter: InputFilter? = null
    private var limitNumber: Int = 0
    private var limitDecimal: Int = 0

    fun setLimitNumber(limitNumber: Int)
    {
        this.limitNumber = limitNumber
        resetLimit()
    }

    fun setLimitDecimal(limitDecimal: Int)
    {
        this.limitDecimal = limitDecimal
        resetLimit()
    }

    fun setMaxLen(max: Int)
    {
        maxLenFilter = LengthFilter(max)
        resetLimit()
    }

    private fun resetLimit()
    {
        val filters = ArrayList<InputFilter>()
        if (maxLenFilter != null)
        {
            filters.add(maxLenFilter!!)
        }
        if (limitNumber > 0 || limitDecimal > 0)
        {
            filters.add(DecimalInputFilter(limitNumber, limitDecimal))
        }
        if (filters.isNotEmpty()) setFilters(filters.toTypedArray())
    }

    fun setFilter(s: String)
    {
        keyListener = DigitsKeyListener.getInstance(s)
    }

    /******************************************* 其他 *******************************************/

    var isAutoVisible: Boolean = false

    fun setAutoText(s: String?)
    {
        if (isAutoVisible) visibility = if (s == null || s.trim().isEmpty()) GONE else VISIBLE
        setText(s)
    }

    fun setClick(isClick: Boolean)
    {
        isAlpha = isClick
        isClickable = isClick
    }

    private var isAlpha = false

    override fun setTextColor(color: Int)
    {
        if (isAlpha)
        {
            val states = arrayOfNulls<IntArray>(3)
            states[0] = intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_pressed)
            states[1] = intArrayOf(android.R.attr.state_enabled, android.R.attr.state_pressed)
            states[2] = intArrayOf(-android.R.attr.state_enabled)
            val alphaColor = (0xbb shl 24) + (color and 0xFFFFFF)
            setTextColor(ColorStateList(states, intArrayOf(color, alphaColor, alphaColor)))
        } else
        {
            super.setTextColor(color)
        }
    }

    private var onText: ((s: String) -> Unit)? = null

    private val addTextChanged by lazy {
        addTextAfterListener()
        {
            onText?.invoke(it)
        }
    }

    fun setTextListener(onText: (s: String) -> Unit)
    {
        this.onText = onText
        addTextChanged
    }

    fun focus()
    {
        isFocusable = true
        isFocusableInTouchMode = true
        clearFocus()
        requestFocus()
        setSelection(text.length)
    }

    /***************************************** 文本样式 ***************************************/

    fun setBold(bold: Boolean)
    {
        typeface = if (bold) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
    }

    fun setItalic(italic: Boolean)
    {
        setTypeface(Typeface.DEFAULT, if (italic) Typeface.ITALIC else Typeface.NORMAL)
    }

    fun setTextStyle(textStyle: String)
    {
        when (textStyle)
        {
            "bold" -> paint.flags = Paint.FAKE_BOLD_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            "delete" -> paint.flags = Paint.STRIKE_THRU_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            "under" -> paint.flags = Paint.UNDERLINE_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            // normal
            else -> paint.flags = Paint.ANTI_ALIAS_FLAG
        }
    }

    fun setTextSize(size: String)
    {
        if (size.endsWith("px"))
        {
            setTextSize(TypedValue.COMPLEX_UNIT_PX, size.replace("px", "").float)
        } else
        {
            setTextSize(TypedValue.COMPLEX_UNIT_DIP, size.float)
        }
    }

    companion object
    {
        val INPUT_TEXT = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
        val INPUT_TEXT_CODE = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
        val INPUT_DECIMAL = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
        val INPUT_NUMBER = InputType.TYPE_CLASS_NUMBER
        val INPUT_PASSWORD = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
    }
}